package ru.passivemoney.indicator.ac;

import java.awt.Color;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.passivemoney.common.Consts;
import ru.passivemoney.indicator.AIndicator;
import ru.passivemoney.indicator.CommonParameters;
import ru.passivemoney.indicator.IndicatorSpecParams;

import com.dukascopy.api.IBar;
import com.dukascopy.api.IIndicators.AppliedPrice;
import com.dukascopy.api.JFException;

public class iAC extends AIndicator {
	private static final Logger logger = LoggerFactory.getLogger(iAC.class);
	
	enum PrognosisTypes{
		iAC_Prognosis_1
	}
	private PrognosisTypes prognosisType;
	
	private List<ValueColor> values = new ArrayList<ValueColor>();
	private List<BigDecimal> prognosis = new ArrayList<BigDecimal>();
	
	private IBar currentBar;
	private int index = 5; // 
	
	public ACSpecParams getSpecParams(){
		return (ACSpecParams)specParams;
	}
	
	public iAC(CommonParameters commonParameters, IndicatorSpecParams specParams) {
		super(commonParameters, specParams);
	}

	public void init() {
		
		logger.info("Initing iAC");
		
		super.init();
		prognosisType = PrognosisTypes.iAC_Prognosis_1;
		
		currentBar = getCurrentBar();
		
		// 
		List<BigDecimal> indicatorValues = new ArrayList<BigDecimal>(Arrays.asList(
				ac(commonParameters.getAppliedPrice(), getSpecParams().getFastPeriod(), getSpecParams().getSlowPeriod(), (int)index)));
		
		for(BigDecimal bd : indicatorValues){
			values.add(new ValueColor(bd, null));
			prognosis.add(BigDecimal.ZERO);
		}
		
		values.get(0).setColor(Color.GRAY);
		for(int i = 1; i < index; i++){
			values.get(i).setColor(getColor(values.get(i-1).getValue(), values.get(i).getValue()));
		}

		logger.info("\r\niAC initial array contains:");
		for(ValueColor vc : values){
			logger.info("Value: " + vc.getValue().doubleValue());
			logger.info("Color: " + vc.getColor());
		}
	}
	
	public BigDecimal getPrognosis() {
		IBar bar = getCurrentBar();
		if(bar == null){
			logger.error("ERROR. BAR is null.");
			return BigDecimal.ZERO;
		}
		
		if(currentBar.getTime() != bar.getTime()){
			logger.info("iAC. Calculating new prognosis...");
			BigDecimal val = ac(commonParameters.getAppliedPrice(), getSpecParams().getFastPeriod(), getSpecParams().getSlowPeriod());
			values.add(new ValueColor(val, getColor(values.get(index-1).getValue(), val)));
			index++;
			currentBar = bar;
		}
		
		if(prognosis.size() == index){
			return prognosis.get(index-1);
		}else{
			switch(getPrognosisType()){
				case iAC_Prognosis_1: {
					getPrognosis_1();
					break;
				}
			}
		}
		
		return prognosis.get(index-1);
	}
	
	private void getPrognosis_1(){
		prognosis.add(Consts.MIN_PROGNOSIS);
		
		if(getValue().compareTo(BigDecimal.ZERO) > 0){ // Выше нуля
			if(getColor().equals(Color.GREEN)){ // зелёный
				if(getValue().compareTo(getValue(index-2)) > 0 && getValue(index-2).compareTo(getValue(index-3)) > 0){
					prognosis.remove(index-1);
					prognosis.add(new BigDecimal(1));
				}
			}else if(getColor().equals(Color.RED)){ // красный
				if(getValue().compareTo(getValue(index-2)) < 0 && getValue(index-2).compareTo(getValue(index-3)) < 0 && getValue(index-3).compareTo(getValue(index-4)) < 0){
					prognosis.remove(index-1);
					prognosis.add(new BigDecimal(-1));
				}
			}
		}else{ // ниже нуля
			if(getColor().equals(Color.RED)){ // красный
				if(getValue().compareTo(getValue(index-2)) < 0 && getValue(index-2).compareTo(getValue(index-3)) < 0){
					prognosis.remove(index-1);
					prognosis.add(new BigDecimal(-1));
				}
			}else if(getColor().equals(Color.GREEN)){ // зелёный
				if(getValue().compareTo(getValue(index-2)) > 0 && getValue(index-2).compareTo(getValue(index-3)) > 0 && getValue(index-3).compareTo(getValue(index-4)) > 0){
					prognosis.remove(index-1);
					prognosis.add(new BigDecimal(1));
				}
			}
		}
		
	}
	
	private Color getColor(BigDecimal oldValue, BigDecimal newValue){
	   if(oldValue.compareTo(BigDecimal.ZERO) == -1 && newValue.compareTo(BigDecimal.ZERO) == 1) return(Color.GREEN);
	   if(oldValue.compareTo(BigDecimal.ZERO) == -1 && newValue.compareTo(BigDecimal.ZERO) == -1 && oldValue.compareTo(newValue) == -1) return(Color.GREEN);
	   if(oldValue.compareTo(BigDecimal.ZERO) == -1 && newValue.compareTo(BigDecimal.ZERO) == -1 && oldValue.compareTo(newValue) == 1) return(Color.RED);
		   
	   if(oldValue.compareTo(BigDecimal.ZERO) == 1 && newValue.compareTo(BigDecimal.ZERO) == -1) return(Color.RED);
	   if(oldValue.compareTo(BigDecimal.ZERO) == 1 && newValue.compareTo(BigDecimal.ZERO) == 1 && oldValue.compareTo(newValue) == 1) return(Color.RED);
	   if(oldValue.compareTo(BigDecimal.ZERO) == 1 && newValue.compareTo(BigDecimal.ZERO) == 1 && oldValue.compareTo(newValue) == -1) return(Color.GREEN);
	   
	   return(Color.GRAY);
	}
	
	private BigDecimal[] ac(AppliedPrice appliedPrice, int fastPeriod, int slowPeriod, int shift) {
		BigDecimal[] out = new BigDecimal[shift];
		double[] singleBar;
		
		for(int i = shift; i > 0; i--){
			try {
				singleBar = getIndicators().ac(commonParameters.getInstrument(), commonParameters.getPeriod(), commonParameters.getOfferSide(), appliedPrice, fastPeriod, slowPeriod, i);
			} catch (JFException e) {
				logger.error("Indicator value can't be calculated", e);
				singleBar = new double[]{0.0, 0.0};
			}
			
			if(singleBar[0] == 0 && singleBar[1] < 0){
				out[shift - i] = new BigDecimal(singleBar[1]);
			}else if(singleBar[0] > 0 && singleBar[1] == 0){
				out[shift - i] =new BigDecimal(singleBar[0]);
			}else{
				logger.error("Bad indicator value");
				out[shift - i] = BigDecimal.ZERO;
			}
		}
		
		for(BigDecimal bd : out){
			logger.info("iAC indicator value : {}", bd.doubleValue());
		}
		return out;
	}
	
	private BigDecimal ac(AppliedPrice appliedPrice, int fastPeriod, int slowPeriod) {
		double[] singleBar;
		try {
			singleBar = getIndicators().ac(commonParameters.getInstrument(), commonParameters.getPeriod(), commonParameters.getOfferSide(), appliedPrice, fastPeriod, slowPeriod, commonParameters.getShift());
		} catch (JFException e) {
			logger.error("Indicator value can't be calculated", e);
			singleBar = new double[]{0.0, 0.0};
		}
		
		BigDecimal out = null;
		
		if(singleBar[0] == 0 && singleBar[1] != 0){
			out = new BigDecimal(singleBar[1]);
		}else if(singleBar[1] == 0 && singleBar[0] != 0){
			out = new BigDecimal(singleBar[0]);
		}else{
			logger.error("Bad indicator value");
			out = BigDecimal.ZERO;
		}
		logger.info("iAC indicator value : {}", out);
		return out;
	}
	
	private BigDecimal getValue(int index){
		return values.get(index).getValue();
	}
	
	private BigDecimal getValue(){
		return getValue(index-1);
	}
	
	private Color getColor(int index){
		return values.get(index).getColor();
	}
	
	private Color getColor(){
		return getColor(index-1);
	}
	
	public PrognosisTypes getPrognosisType() {
		return prognosisType;
	}

	public void setPrognosisType(PrognosisTypes prognosisType) {
		this.prognosisType = prognosisType;
	}

	class ValueColor{
		BigDecimal value;
		Color color;
		
		public ValueColor(BigDecimal value, Color color) {
			super();
			this.value = value;
			this.color = color;
			logger.info("iAC new ValueColor: {}, {}", value.doubleValue(), color);
		}
		public BigDecimal getValue() {
			return value;
		}
		public void setValue(BigDecimal value) {
			this.value = value;
		}
		public Color getColor() {
			return color;
		}
		public void setColor(Color color) {
			this.color = color;
		}
		
	}

}
